package com.hontech.libratest.conn

import com.hontech.libratest.env.DeliveryProgEvent
import com.hontech.libratest.env.ExceptEvent
import com.hontech.libratest.model.DeviceStatus
import com.hontech.libratest.model.RkcStatus
import com.hontech.libratest.utils.*
import java.io.IOException

class PortReader(val port: FtdiSerialDevice, val sync: Sync, val respSync: RespSync) : Thread() {

    override fun run() {

        while (true) {

            try {
                exec()
            } catch (e: IOException) {
                e.printStackTrace()
                break
            } catch (e: IllegalStateException) {
                e.printStackTrace()
            }
        }
        log("reader退出")
    }

    private fun exec() {
        val frame = read()
        if (frame.src != Device.destAddr) {
            return
        }
        dispatch(frame)
    }

    private fun dispatch(frame: Frame) {
        val req = frame.request()

        if (req == Proto.Ack) {
            sync.signal()
            return
        }

        if (!frame.isNotify()) {
           // log("recv:$frame")
            respSync.signal(frame)
            return
        }

        when (req) {
            Proto.RkcStatus -> {
                RkcStatus.recv(frame)
            }
            Proto.DevStatus -> {
                DeviceStatus.recv(frame)
            }
            Proto.Except -> {
                onExcept(frame)
            }
            Proto.Delivery -> {
                onProg(frame)
            }
        }
    }

    private fun onProg(frame: Frame) {
        val prog = UInt8()
        val ec = UInt8()
        frame.parse(arrayOf(prog, ec))
        eventBus.post(DeliveryProgEvent(prog.value, ec.value))
    }

    private fun onExcept(frame: Frame) {
        val ec = UInt8()
        val bw = ByteView()
        frame.parse(arrayOf(ec, bw))
        eventBus.post(ExceptEvent(ec.value, bw.toString()))
    }

    private fun read(): Frame {
        sync()
        val headBuf = port.read(6)
        val len = headBuf.toUInt16(0)
        if (len < 10) {
            throw IllegalStateException("协议长度错误 <10:$len")
        }
        val buf = port.read(len - 8)
        val s = buf.xorSum(0, len - 10)
        if (s != buf.toUInt8(len - 8 - 2)) {
            throw IllegalStateException("校验和错误")
        }

        if (Proto.End != buf.toUInt8(len - 8 - 1)) {
            throw IllegalStateException("协议尾错误")
        }

        val dest = headBuf.toUInt8(2)
        val src = headBuf.toUInt8(3)
        val req = headBuf.toUInt16(4)

        return Frame(dest, src, req, buf)
    }

    private fun sync() {
        var flag = false
        while (true) {
            val head = port.readByte()
            if (flag && (head == Proto.Head1)) {
                return
            }
            flag = (head == Proto.Head0)
        }
    }
}